/* Declarations for builtin functions.

   This file is part of khipu.

   khipu is free software: you can redistribute it and/or modify
   it under the terms of the GNU Lesser General Public License as published by
   the Free Software Foundation; either version 3 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU Lesser General Public License for more details.

   You should have received a copy of the GNU Lesser General Public License
   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */

#ifndef __KP_BUILTINS__
#define __KP_BUILTINS__   1

#include "interp.hpp"
#include "initop.hpp"

KP_DECLS_BEGIN

// Basic routine to copy any object.
KP_EXPORT result<object> copy (interpreter *interp,
                               object obj, bool deep = false);

// Hash a generic object.
KP_EXPORT result<uint32_t> xhash (interpreter *interp, object obj);

// Hash an object as an address.
KP_EXPORT uint32_t hash_addr (object obj);

// Return the length of a generic object.
KP_EXPORT result<object> length (interpreter *interp, object obj);

// Add objects X and Y.
KP_EXPORT result<object> add (interpreter *interp, object x, object y);

// Subtract object Y from X.
KP_EXPORT result<object> sub (interpreter *interp, object x, object y);

// Multiply objects X and Y.
KP_EXPORT result<object> mul (interpreter *interp, object x, object y);

// Divide object X by Y.
KP_EXPORT result<object> div (interpreter *interp, object x, object y);

// Return the modulo of X by Y.
KP_EXPORT result<object> modulo (interpreter *interp, object x, object y);

// Test for object equality.
KP_EXPORT result<bool> equal (interpreter *interp, object x, object y);

// Compare 2 objects.
KP_EXPORT result<int> xcmp (interpreter *interp, object x, object y);

#define DEFBUILTIN(name)   \
  KP_EXPORT result<object> name (interpreter *interp, object *argv, int argc)

// Make a generic exception for bootstrapping.
DEFBUILTIN (p_mkexc);

// Make a list out of the arguments in the stack.
DEFBUILTIN (list_fct);

/* Make a list out of the arguments in the stack, chaining it
 * to the last one, which must be a list as well. */
DEFBUILTIN (list_star);

// Make a tuple out of the arguments in the stack.
DEFBUILTIN (tuple_fct);

// Make a table out of the arguments in the stack.
DEFBUILTIN (table_fct);

// Perform addition for every object.
DEFBUILTIN (add_fct);

// Perform subtraction for every object.
DEFBUILTIN (sub_fct);

// Perform multiplication for every object.
DEFBUILTIN (mul_fct);

// Perform division for every object.
DEFBUILTIN (div_fct);

// Call function with list of arguments.
DEFBUILTIN (apply_fct);

// Create an array out of the arguments on the stack.
DEFBUILTIN (array_fct);

// Create a table out of the arguments on the stack.
DEFBUILTIN (table_fct);

// Create a tree out of the arguments on the stack.
DEFBUILTIN (tree_fct);

// Add a global definition for a symbol.
DEFBUILTIN (p_putd);

// Reverse an object.
DEFBUILTIN (reverse_fct);

// Reverse an object inplace, destructively.
DEFBUILTIN (nreverse_fct);

// Modify an object at an index, inplace.
DEFBUILTIN (nput_fct);

// Construct a subsequence.
DEFBUILTIN (subseq_fct);

// Mutate a collection value for a key.
DEFBUILTIN (nzap_fct);

// Exit khipu.
DEFBUILTIN (exit_fct);

#undef DEFBUILTIN

typedef result<object> (*indexer_t) (interpreter *, object, object, object);

KP_EXPORT indexer_t index_seq (object seq);

struct builtin_iter
{
  const char *curp;

  builtin_iter ();
  const char *name () const
    {
      return (this->curp);
    }

  void adv ();
  bool valid () const;
};

// Utility for the sorting functions.
struct comparator
{
  interpreter *interp;

  comparator (interpreter *ip) : interp (ip)
    {
    }

  virtual result<bool> operator() (object x, object y)
    {
      int c = KP_TRY (xcmp (this->interp, x, y));
      return (c < 0);
    }
};

// Init OP for builtins.
KP_EXPORT init_op init_builtins;

KP_DECLS_END

#endif
